/**
  @file: SettingsFileList.java

  PURPOSE: 
  A SettingsFileList is a regular file that is expected to contain paths to one
  or more configuration settings files. Each is read and loaded into this
  object.

  The lines of the filelist may reference a fully qualified path (start with
   '/'), or otherwise, be a relative path from the installation root
   directory. Any blank lines in the file are ignored, and any line with a
   '#' in the first column are comments, and ignored.
   
  @author Ron Williams

  REVISION HISTORY ABSTRACT

  PROGRAMMER:  Ron Williams           ORG: MSE

  Copyright 2011 Mission Solutions LLC. All rights reserved.

  END ABSTRACT
 */
package com.mse.utilities;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.mse.utilities.SettingsKeys;
import com.mse.utilities.UtilityException;

/**
  DESCRIPTION:
  This class defines a single, global source for all program settings.
 */
public class SettingsFileList {
   
   /**
     DESCRIPTION:
     Constructs an instance of a SettingsFileList. All settings files defined
     in the filePath are read as properties.

     @param filePath - path to a filelist file
     @throws UtilityException - for any error reading the filelist file or in
                              processing their settings
    */
   public SettingsFileList(String filePath) throws UtilityException {
      File aFile = new File(filePath);

      if (! (aFile.isFile() && aFile.canRead()) ) {
         throw new UtilityException("*** FAILED to access filelist file: " +
                                     aFile.getPath());
      }

      List<String> fList = parseFileList(filePath);

      theStore = new HashMap<String,String>();
      loadProperties(fList);
   }
   
   /**
     DESCRIPTION:
     This method returns all properties obtained by reading a filelist.
   
     @return props - a properties object resulting from reading settings from
                     all definitions in a filelist.
    */
   public Map<String,String> getFileListSettings() {
      return theStore;

   }
   
   /**
     DESCRIPTION:
     This method parses a filelist file and assembles a list of paths to 
     settings files.
   
     @param fListPath  - a path to the filelist to parse
     @return fList - a list of paths to files to be processed.
     @throws UtilityException - for error reading a filelist
    */
   private List<String> parseFileList(String fListPath)
      throws UtilityException {

      ArrayList<String> fList = new ArrayList<String>();
      String aLine;
      String deployRoot = SettingsKeys.getDeployRoot() + File.separator;

      // read lines from the filelist file, slip blank lines and comment lines
      // paths that do NOT start with '/' are prefixed with the installation
      // root directory path.
      try {
         BufferedReader BR = new BufferedReader(new InputStreamReader(
                              new FileInputStream(fListPath)));
         boolean notDone = true;
         while (notDone) {
            try {
               aLine = BR.readLine();
               if (aLine == null) {
                  notDone = false;
               } else {
                  // parse this line, skip blank lines and comments
                  if (! aLine.isEmpty()) {
                     if ( (aLine.charAt(0) != '#') &&
                          (aLine.charAt(0) != ' ')) {
                        // we have a file definition, append deploy root if
                        // necessary
                        if (aLine.charAt(0) != '/') {
                           fList.add(deployRoot + aLine);
                        } else {
                           fList.add(aLine);
                        }
                     }
                  }
               }
            } catch (IOException ioe) {
               BR.close();
               throw new UtilityException("Error reading filelist file: " +
                                           fListPath);
            }
         }

         BR.close();

      } catch (FileNotFoundException fnf) {
         throw new UtilityException("Could not access Filelist file: " +
                                     fListPath);
      } catch (IOException ioe) {
         throw new UtilityException("Could not close Filelist file: " +
                                     fListPath);
      }

      return fList;
   }

   /**
     DESCRIPTION:
     This method loads properties from each path in the filelist. All properties
     are kept in our store.
   
     @param fList  - a list of paths to files to load
     @throws UtilityException - for error reading a filelist property file
    */
   private void loadProperties(List<String> fList) throws UtilityException {
      Properties props;
      String     key;
      Enumeration<String> itor;

      // get all property settings from each file
      for (String path : fList) {
         props = new Properties();
         try {
            props.load(new FileInputStream(path));
            itor = (Enumeration<String>) props.propertyNames();

            while (itor.hasMoreElements()) {
               key = itor.nextElement();
               theStore.put(key, props.getProperty(key));
            }
         } catch (IOException ioe) {
            throw new UtilityException("Could not load Filelist file: " +
                                        path);
         }
      }
   }

   //-------------------------------------------------------  PRIVATE

   private HashMap<String,String> theStore;  // keep all properties read here

}
